package main

import "fmt"

/*
  访问者模式
  创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。
  将定义另一个接口 ComputerPartVisitor，它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。
  例子
  使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法
*/

//组件
type ComputerPart interface {
	Accept(computerPartVisitor ComputerPartVisitor)
}

//键盘
type Keyboard struct {
}

func (k *Keyboard) Accept(computerPartVisitor ComputerPartVisitor) {
	computerPartVisitor.VisitKeyboard(k)
}
//监控
type Monitor struct {
}

func (m *Monitor) Accept(computerPartVisitor ComputerPartVisitor) {
   computerPartVisitor.VisitMonitor(m)
}
//鼠标
type Mouse struct {
}

func (m *Mouse) Accept(computerPartVisitor ComputerPartVisitor) {
    computerPartVisitor.VisitMouse(m)
}
//计算机
type Computer struct {
	parts []ComputerPart
}

func NewComputer() *Computer {
	parts := make([]ComputerPart,0)
	parts = append(parts,&Keyboard{},&Monitor{},&Mouse{})
	return &Computer{parts:parts}
}

func (c *Computer) Accept(computerPartVisitor ComputerPartVisitor) {
	for _,v := range c.parts {
		v.Accept(computerPartVisitor)
	}
	//访问者访问
	computerPartVisitor.VisitComputer(c)
}

type ComputerPartVisitor interface {
	VisitComputer(computer *Computer)
	VisitKeyboard(keyboard *Keyboard)
	VisitMonitor(monitor *Monitor)
	VisitMouse(mouse *Mouse)
}

type ComputerPartDisplayVisitor struct {
}

func (c ComputerPartDisplayVisitor) VisitComputer(computer *Computer)  {
	fmt.Println("Displaying Computer")
}
func (c ComputerPartDisplayVisitor) VisitKeyboard(keyboard *Keyboard)  {
	fmt.Println("Displaying Keyboard")
}
func (c ComputerPartDisplayVisitor) VisitMonitor(monitor *Monitor)  {
	fmt.Println("Displaying Monitor")
}
func (c ComputerPartDisplayVisitor) VisitMouse(mouse *Mouse)  {
	fmt.Println("Displaying Mouse")
}

func main() {
	computer := NewComputer()
	computer.Accept(ComputerPartDisplayVisitor{})
}
